#!python

import os
import shutil
import string

import gen_graphs


parameters = {
    'QUOTA'               : [50, 100, 150],
    'STATIC_AGENTS'       : [0, 5, 20],
    'ADAPTIVE_AGENTS'     : [0, 5, 20],
    'PLOT_UPD_MULTIPLIER' : [3, 10],
    'STRATEGY_GENERATOR'  : ['strategies.LocalOptimumStrategyGenerator', 'strategies.PointOfOriginStrategyGenerator']
}

# {(<nodes>, <edges>, <resource nodes dispersion>, <yield dispersion>): <number of graphs>, ...}
scenarios = {
    ( 5,   6, 1.0, 0.0): 3,
    (15,  50, 1.0, 0.0): 3,
    (15,  75, 1.0, 0.0): 3,
    (20, 100, 1.0, 0.0): 3,
    (20, 150, 1.0, 0.0): 3,
    (30, 400, 1.0, 0.0): 3
}


out_file = 'out.log'
config_file = 'custom.config'
tmp_data_file = '../data/data.tmp'
RUN_TEMPLATE = "java -cp .;..\lib\collections-generic-4.01.jar;..\lib\jung-api-2.0.1.jar;..\lib\jung-graph-impl-2.0.1.jar;..\lib\jung-io-2.0.1.jar;tragedy.jar base.Main %s/%s > %s/%s"
MAX_YIELD = 100
LEARNING_STEPS = 2000


# http://stackoverflow.com/questions/533905/get-the-cartesian-product-of-a-series-of-lists-in-python
def product(args):
    if not args:
        return iter(((),))
    return (items + (item,) for items in product(args[:-1]) for item in args[-1])

def generate_graphs(scenarios, max_yield):
    graphs = {}
    for ((nodes, edges, nodes_dispersion, yield_dispersion), iterations) in scenarios.iteritems():
        for id in range(1, iterations + 1):
            name = "g%d_%d_%.2f_%.2f#%d" % (nodes, edges, nodes_dispersion, yield_dispersion, id)
            graphs[name] = \
                gen_graphs.gen_graph(nodes, edges, nodes_dispersion, yield_dispersion, max_yield)
    return graphs

def prepare_test(graph_id, graph, params, param_keys):
    
    no_agents = True
    for i in range(0, len(params)):
        if param_keys[i] == 'STATIC_AGENTS' and params[i]:
            no_agents = False
            break
        if param_keys[i] == 'ADAPTIVE_AGENTS' and params[i]:
            no_agents = False
            break
    if no_agents:
        return None
    
    test = '../data/test_%s_' % graph_id
    for i in range(0, len(params)):
        test += '_' + param_keys[i][0] + str(params[i]).split("/")[-1]
    print test
    
    if not os.path.exists(test):
        os.makedirs(test)
    
    gen_graphs.dump_graph(graph, "%s/%s.plots" % (test, graph_id))
    
    config = open(test + '/' + config_file, 'w')
    config.write('# %s\n' % (test))
    config.write('PLOTS_FILE = %s/%s.plots\n' % (test, graph_id))
    config.write('DEBUG_MODE = false\n')
    config.write('UI_MODE = false\n')
    for i in range(0, len(params)):
        config.write('%s = %s\n' % (param_keys[i], params[i]))
    config.close()
        
    return test


def parse_agent(line):
    return line[3:string.find(line, '#')-1]


def dump_metrics(stream, metrics):
    stream.write('%s\t\t\t%s\t\t\t%s\t\t\t%s\t\t\t%s\n' %
                    (metrics['@ Environment Damage'],
                     metrics['@ Resource Usage Efficiency'],
                     metrics['@ Quota Fulfillment'],
                     metrics['@ Quota Classes'],
                     metrics['@ Quota Norm']))


def parse_output(test, params):
    
    factor = float(params['QUOTA'])
    file = open(test + '/' + out_file)
    
    utility_file = open(test + '/learning_utility.dat', 'w')
    utility_file.write('# Agent Harvesting Utilities\n')
    utility_file.write('# Static\tAdaptive\n')
    metrics_file = open(test + '/learning_metrics.dat', 'w')
    metrics_file.write('# Environmental and Agent Metrics\n')
    metrics_file.write('# Environment Damage\tResource Usage Efficiency\t' + \
                       'Quota Fulfillment\tQuota Classes\tQuota Norm\n')
    metrics = {'@ Environment Damage':        0.0,
               '@ Resource Usage Efficiency': 0.0,
               '@ Quota Fulfillment':         0.0,
               '@ Quota Classes':             0.0,
               '@ Quota Norm':                0.0}
    agents = {'StaticAgent': (0, 0.0), 'AdaptiveAgent': (0, 0.0)}
    step = 1;
    
    while True:
        line = file.readline()
        if line[0] == '@':
            
            if string.find(line, '@ CONVERGENCE:') == 0:
                break
            
            if line[0:2] == '@@' and line[-2] != ':':
                agent = parse_agent(line)
                agents[agent] = (agents[agent][0] + 1, \
                                 agents[agent][1] + float(line.split("utility=")[1].split(";")[0]))
            
            elif string.find(line, '@ STEP') == 0:
                step += 1
                if line[7] != '0':
                    static_utility = None
                    if 'STATIC_AGENTS' in params and params['STATIC_AGENTS'] > 0:
                        static_utility = agents['StaticAgent'][1] / agents['StaticAgent'][0] / factor / step
                    adaptive_utility = None
                    if 'ADAPTIVE_AGENTS' in params and params['ADAPTIVE_AGENTS'] > 0:
                        adaptive_utility = agents['AdaptiveAgent'][1] / agents['AdaptiveAgent'][0] / factor / step
                    if not static_utility:
                        aux = "\t\t%f\n" % adaptive_utility
                    elif not adaptive_utility:
                        aux = "%f\t\t\n" % static_utility
                    else:
                        aux = "%f\t\t%f\n" % (static_utility, adaptive_utility)
                    utility_file.write(aux)
                    agents = {'StaticAgent': (0, 0.0), 'AdaptiveAgent': (0, 0.0)}
                    dump_metrics(metrics_file, metrics)
            else:
                for metric in metrics.iterkeys():
                    if string.find(line, metric) == 0:
                        begin = string.find(line, ':') + 2
                        end = string.find(line, '%')
                        if end < 0:
                            end = len(line)
                        metrics[metric] = float(line[begin : end])
                        break
    
    step += 1
    static_utility = None
    if 'STATIC_AGENTS' in params and params['STATIC_AGENTS'] > 0:
        static_utility = agents['StaticAgent'][1] / agents['StaticAgent'][0] / factor / step
    adaptive_utility = None
    if 'ADAPTIVE_AGENTS' in params and params['ADAPTIVE_AGENTS'] > 0:
        adaptive_utility = agents['AdaptiveAgent'][1] / agents['AdaptiveAgent'][0] / factor / step
    if not static_utility:
        aux = "\t\t%f\n" % adaptive_utility
    elif not adaptive_utility:
        aux = "%f\t\t\n" % static_utility
    else:
        aux = "%f\t\t%f\n" % (static_utility, adaptive_utility)
    utility_file.write(aux)
    utility_file.close();
    dump_metrics(metrics_file, metrics)
    metrics_file.close();
    
    # completely retarded
    shutil.copy2(test + '/learning_utility.dat', tmp_data_file)
    os.system('gnuplot utility.p')
    shutil.move('../data/utility.gif', test + '/learning_utility.gif')
    os.remove(tmp_data_file)
    shutil.copy2(test + '/learning_metrics.dat', tmp_data_file)
    os.system('gnuplot metrics.p')
    shutil.move('../data/metrics.gif', test + '/learning_metrics.gif')
    os.remove(tmp_data_file)


if __name__ == '__main__':
    
    os.system("jar -cvfe tragedy.jar base.Main -C ../bin/ .")
    os.system("if not exist conf mkdir conf")
    os.system("copy ..\\conf\\default.config conf\\default.config")
    os.system("copy ..\\conf\\default.plots conf\\default.plots")
    
    graphs = generate_graphs(scenarios, MAX_YIELD)
    for (graph_id, graph) in graphs.iteritems():
#        print "\n\n", graph_id
#        print graph.toprettyxml(indent="    ", encoding="UTF-8")
    
        for params in product(parameters.values()):
            test = prepare_test(graph_id, graph, params, parameters.keys())
            if not test:
                continue # no agents...
            
            if os.system(RUN_TEMPLATE % (test, config_file, test, out_file)):
                continue # it happens...
            
            mapped_params = dict()
            for i in range(0, len(params)):
                mapped_params[parameters.keys()[i]] = params[i]
            
            parse_output(test, mapped_params)
    
    print "\n\nFinished simulations!"
